# coding:utf-8
# import pytesseract
from selenium.webdriver.common.keys import Keys

__author__ = 'wangxiang'

import functools
import os
import platform
import time

from selenium import webdriver
from selenium.webdriver import Remote
from selenium.common.exceptions import NoSuchElementException, TimeoutException
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait
# import PIL
# import pytesseract
from utils.logger import Logger
from utils.settting import ensure_path_sep


class BasePage(object):

    def __init__(self, driver=None):
        """
        初始化操作
        :param driver: 默认值为None，默认新起一个webdriver；若不想新打开webdriver，则通过此变量传入已有driver
        """
        if driver is None:

            if platform.system() == 'Darwin':
                Logger.info('Mac')
                self.driver = webdriver.Chrome(ensure_path_sep('chrome/chromedriver_mac'))
            elif platform.system() == 'Windows':
                Logger.info('Windows')
                # chrome_options = webdriver.ChromeOptions()
                # chrome_options.add_argument('--headless')
                # chrome_options.add_argument('lang=zh_CN.UTF-8')

                self.driver = webdriver.Chrome(ensure_path_sep('/chrome/chromedriver.exe'))
            elif platform.system() == 'Linux':
                Logger.info('Linux')
                chrome_options = webdriver.ChromeOptions()
                chrome_options.add_argument('--headless')
                chrome_options.add_argument('--disable-gpu')
                chrome_options.add_argument('window-size=1920x1080')
                chrome_options.add_argument('--disable-dev-shm-usage')
                chrome_options.add_argument('--no-sandbox')
                chrome_options.add_argument('lang=zh_CN.UTF-8')
                self.driver = webdriver.Chrome(os.path.join(configs.config.basedir, 'chrome', 'chromedriver_linux'),
                                               chrome_options=chrome_options)
            else:
                Logger.info('不支持的系统!')
            self.driver.set_window_size(1920, 1920)
            self.driver.maximize_window()

        else:
            self.driver = driver

        # self.imagedir = configs.config.Config.imagePath

    # 高亮
    def highlight(func):

        # def apply_style(element):
        # 实现的方式很简单，就是定位到元素后，执行js样式
        # self.driver.execute_script("arguments[0].style.border='6px solid red'", element)
        @functools.wraps(func)
        def wrapper(self, *args, **kwargs):
            try:
                element = func(self, *args, **kwargs)
                # apply_style(element)
                self.driver.execute_script("arguments[0].style.border='3px solid red'", element)
                return element
            except Exception as e:
                print(e)

        return wrapper

    def open(self, url, Logger=None):
        """
        打开url
        :param url:页面url
        :param Logger:日志信息
        :return:
        """
        if Logger:
            print(Logger)
        self.driver.get(url)

    def sleep(self, timeout):
        """
        等待
        :param timeout:秒
        :return:
        """
        time.sleep(timeout)

    def assert_element_exits(self, locator, Logger=None, timeout=2):
        """
        校验页面元素是否存在
        :param locator: 页面元素
        :param timeout: 等待时间，默认2s
        :param Logger: Logger信息
        :return:
        """
        try:
            WebDriverWait(driver=self.driver, timeout=timeout).until(
                EC.visibility_of_element_located(locator=locator))
            if Logger:
                print(Logger + ':成功')
            return True
        # except (NoSuchElementException, TimeoutException):
        #     print(Logger + ':失败')
        #     raise AssertionError
        except Exception as e:
            print(e)
            return False

    def find_element(self, *locator, timeout=None):
        """
        查找页面元素
        :param locator:
        :return:
        """
        if timeout == None:
            timeout = 20
        try:
            return WebDriverWait(driver=self.driver, timeout=timeout).until(
                EC.visibility_of_element_located(locator=locator))

        except (NoSuchElementException, TimeoutException):
            self.screenshot('error')
            raise TimeoutException(msg='寻找元素失败, 定位方式为: {}'.format(locator))

    def find_elements(self, *locator, timeout=None):

        if timeout == None:
            timeout = 20
        try:
            return WebDriverWait(driver=self.driver, timeout=timeout).until(
                EC.visibility_of_all_elements_located(locator=locator))
        except (NoSuchElementException, TimeoutException):
            self.screenshot('error')
            raise TimeoutException(msg='寻找元素失败, 定位方式为: {}'.format(locator))

    def highLightElement(self, element):
        self.driver.execute_script("arguments[0].setAttribute('style',arguments[1]);",
                                   element, "border:2px solid red;")

    def get_elements(self, by, value, wait=True):
        """
                查找页面元素
                :param locator:
                :return:
                """
        if wait:
            try:
                if WebDriverWait(driver=self.driver, timeout=20).until(
                        EC.visibility_of_element_located(locator=(by, value))):
                    return self.driver.find_elements(by, value)
            except (NoSuchElementException, TimeoutException):
                # self.driver.quit()
                return self.driver.find_elements(by, value)
        else:
            return self.driver.find_elements(by, value)

    def get_menu_content(self, xpathExpression, queryContent, index, linetype='tr', coltype='td'):
        # 按行查询表格的数据，取出的数据是一整行，按空格分隔每一列的数据
        element = None
        li_list = self.driver.find_element(By.XPATH, xpathExpression).find_elements(By.TAG_NAME, linetype)
        for rindex, li in enumerate(li_list):  # 遍历每一个tr
            # 将每一个tr的数据根据td查询出来，返回结果为list对象
            elements = li.find_elements(By.TAG_NAME, coltype)
            # elements = elements[0].find_elements(By.TAG_NAME, "span")
            for dindex, span in enumerate(elements):
                # print(dindex,span.get_attribute('id'))
                if queryContent == span.text:
                    return elements[dindex - 1 + index]

    def click(self, locator, Logger=None, retry=0):
        """
        点击操作
        :param locator: 页面元素
        :param Logger: 日志信息
        :return:
        """

        if Logger:
            print(Logger)
        try:
            element = self.find_element(*locator)
            # self.highLightElement(element)
            element.click()
            self.sleep(0.5)
        except BaseException as e:
            if retry == 0:
                print(e)
            else:
                self.click(*locator, retry=retry - 1)

    def change(self):

        self.driver.change()

    def sendKeys(self, locator, value, Logger=None):
        """
        文本框输入
        :param locator: 页面元素
        :param value: 输入的值
        :param Logger: 日志信息
        :return:
        """

        if Logger:
            print(Logger)
        element = self.find_element(*locator)

        self.highLightElement(element)
        # element.clear()
        element.send_keys(value)
        self.sleep(1)

    def cleartext(self, locator, Logger=None):
        """
        清除文本框
        :param locator: 页面元素
        :param Logger: 日志信息
        :return:
        """
        if log:
            print(log)
        self.find_element(*locator).clear()

    def selection_select(self, locator1, locator2, content, log=None):
        """
        选择下拉框中的指定元素
        :param locator1: 下拉框的定位方式
        :param locator2: 下拉框ul元素的定位方式
        :param content: 需要选中的下拉框值
        :param log:
        :return:
        """
        if log:
            print(log)
        ele = self.find_element(*locator1)
        if ele:
            ele.click()
        else:
            print('【ERROR】下拉框没有定位到，请检查！')
        linetype = 'li'
        all_li = []
        li_list = self.find_element(*locator2).find_elements(By.TAG_NAME, linetype)
        for rindex, li in enumerate(li_list):  # 遍历每一个li
            # 将每一个li的数据查询出来，返回结果为list对象
            all_li.append(li.text)
            if content == li.text:
                print('点击文本值:{}'.format(content))
                li.click()
                self.sleep(2)

    def selection_click(self, locator1, locator2, log=None):
        """
        :param locator1: 定位下拉框
        :param locator2: 点击指定的下拉框元素值
        :param log: 输出日志
        :return:
        """

        if log:
            print(log)
        self.click(locator1)
        self.sleep(1)
        self.click(locator2)

    @highlight
    def focusElement(self, locator, log=None):
        """
        聚焦到元素
        :param locator:
        :return:
        """
        if log:
            print(log)
        try:
            element = self.find_element(*locator)
            self.exejs('arguments[0].scrollIntoView();', element)
            self.sleep(1)
            return element
        except Exception as e:
            print(e)

    def text_value(self, locator, log=None):
        """
        :param locator: 页面元素定位方式
        :param log: 打印日志
        :return:
        """
        if log:
            print(log)
        try:
            element = self.find_element(*locator)
            # self.highLightElement(element)
            value = element.text
            self.sleep(0.5)
            return value
        except Exception as e:
            print(e)

    def input_value(self, locator, log=None):
        """
        :param locator: input框定位方式
        :param log:输出的日志
        :return:适用于同步的文本框没有直接在xml显示value
        """
        if log:
            print(log)
        try:
            value = self.find_element(*locator).get_attribute("value")
            return value
        except Exception as e:
            print(e)

    def getText(self, locator, log=None):
        """
        获取页面元素的text
        :param locator:
        :param log:
        :return:
        """
        if log:
            print(log)
        return self.find_element(*locator).text

    def enter(self, locator, log=None):
        """
        回车
        :param locator:
        :param log:
        :return:
        """
        if log:
            print(log)
        return self.find_element(*locator).send_keys(Keys.ENTER)

    def esc(self, locator, log=None):
        """
        回退
        :param locator:
        :param log:
        :return:
        """
        if log:
            print(log)
        return self.find_element(*locator).send_keys(Keys.ESCAPE)

    @highlight
    def getElementByText(self, message):
        """
        通过text获取元素
        :param message:
        :return:
        """

        if message:
            try:
                name = '//*[text()="{}"]'.format(message)
                return self.driver.find_element_by_xpath(name)
            except:
                return self.find_element(*(By.XPATH, '//*[contains(text(),"{}")]'.format(message)), timeout=2)

        # try:
        #     return self.find_element(*(By.XPATH, '//*[text()="{}"]'.format(message)), timeout=2)
        # except:
        #     return self.find_element(*(By.XPATH, '//*[contains(text(),"{}")]'.format(message)), timeout=2)

    @highlight
    def by_text(self, message):
        message = '//*[text()="{}"]'.format(message)
        return self.driver.find_element_by_xpath(message)

    def click_element_by_text(self, text, log=None):
        """
        通过文本获取元素并点击
        :param text:文本
        :param log:
        :return:
        """
        if log:
            print(log)
        ele = self.getElementByText(text)
        if ele:
            self.driver.execute_script('arguments[0].click();', ele)
            time.sleep(0.5)
        else:
            print('通过文本：{}获取元素失败!'.format(text))
            self.screenshot('error')

    def selectoption(self, locator, item, log=None):

        if log:
            print(log)
        select = self.find_element(*locator)
        allOptions = select.find_elements_by_tag_name("option")
        allOptions[item].click()
        # return allOptions[item].text

    def select_by_text(self, locator, text, log=None):
        """
        通过文本方式选择下拉框里的内容
        :param locator:下拉框定位方式
        :param text:文本
        :param log:
        :return:
        """
        if log:
            print(log)
        select = self.find_element(*locator)
        select_text = select.find_elements_by_xpath('//option[text()="' + text + '"]')

        try:
            select_text[0].click()
            time.sleep(1)
        except:
            print('未找到' + text)
            self.screenshot('error')
        # return allOptions[item].text

    def seek_help_select_by_text(self, locator, text, log=None):
        """
        通过文本方式选择下拉框里的内容
        :param locator:下拉框定位方式
        :param text:文本
        :param log:
        :return:
        """
        if log:
            print(log)
        select = self.find_element(*locator)
        select_text = select.find_elements_by_xpath('//option[text()="' + " " + text + "  " + '"]')

        try:
            select_text[0].click()
            time.sleep(1)
        except:
            print('未找到' + text)
            self.screenshot('error')

    # 在元素下找元素
    def element_son(self, element, type, any, log=None):
        if log:
            print(log)
        father = element
        try:
            if type == 'text':
                son = father.find_elements_by_xpath('//*[text()="' + any + '"]')
                # print("==", son)
            son[0].click()
            time.sleep(1)
        except:
            print('未找到' + any)

    def screenshot(self, filename='error'):
        """
        :param filename:
        :return:截屏,截图
        """
        return self.driver.save_screenshot(os.path.join(
            self.imagedir,
            str(filename) + '_' + str(time.strftime('%Y%m%d%H%M%S', time.localtime(time.time()))) + '.png'))

    def slide_bottom(self):
        """
         页面滑动到底部
        """
        self.driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")

    def side_top(self):
        """
          滑动到顶部
        """
        js = "var q=document.documentElement.scrollTop=0"
        self.driver.execute_script(js)

    def page_slide(self, loactor, log=None):
        """
        页面滚动到指定元素位置
        :param loactor: 想要找到的元素位置
        :param log:
        :return:
        """

        if log:
            print(log)
        target = self.find_element(*loactor)
        if target:
            self.driver.execute_script("arguments[0].scrollIntoView();", target)  # 拖动到可见的元素去
            time.sleep(1)
        else:
            print('页面滚动位置：{}获取元素失败!'.format(loactor))

    def eleshot(self, locator, filename='pic'):
        """
        元素截图并识别为字符
        :param locator:
        :param filename:
        :return:
       """

        # 元素坐标
        location = self.focusElement(locator).location
        x = location['x']
        y = location['y']
        # 元素高度宽度
        elesize = self.focusElement(locator).size
        width = elesize['width']
        height = elesize['height']

        paths = os.path.join(
            self.imagedir,
            str(filename) + '_' + str(time.strftime('%Y%m%d%H%M%S', time.localtime(time.time()))) + '.png')
        self.driver.save_screenshot(paths)
        # im = Image.open(paths)
        #
        # if platform.system() == 'Darwin':
        #     im = im.crop((x * 2, y * 2, (x + width) * 2, (y + height) * 2))
        #     print('坐标:', x * 2, y * 2, width * 2, height * 2)
        # elif platform.system() == 'Windows':
        #     im = im.crop((x, y, (x + width), (y + height)))
        #     print('坐标:', x, y, width, height)
        #
        # im.save(paths)
        # img = pytesseract.image_to_string(im)
        # if img == '':
        #     print('无法识别,请查看截图是否正确')
        # else:
        #     print('图片字符为:', img)
        # return img

    def exejs(self, script, *args):
        """
        执行js
        :param script:
        :param args:
        :return:
        """
        self.driver.execute_script(script, *args)
        # js执行button点击
        # button = self.dr.findElement('/html/body/div[2]/div/button')
        # self.dr.exejs("$(arguments[0]).click()", button)

    def input_style(self, locator):
        """
        :param locator: 定位元素的方式
        :return: 修改被隐藏的输入框属性
        """
        js = self.driver.find_element_by_xpath(locator)

        if js:
            self.driver.execute_script("arguments[0].style.display = 'block';", js)
            time.sleep(2)
            print("修改属性成功")

        else:
            print("修改属性失败")

    def find_toast(self, message):
        """
        定位toast
        :param message:
        :return:
        """
        message = '//*[text()="{}"]'.format(message)
        try:
            print(message)
            element = WebDriverWait(self.driver, 5, 0.5) \
                .until(EC.presence_of_element_located((By.XPATH, message)))
            # .until(expected_conditions.presence_of_element_located((By.PARTIAL_LINK_TEXT, message)))
            print(element)
            return True
        except Exception as e:
            Log.error(str(e))
            return False

    def isPresent(self, locator):
        ll = self.find_element(*locator)
        if ll == []:
            return False
        else:
            return True

    def isSelected(self, locator):
        return self.find_element(*locator).is_selected()

    def isDisplayed(self, locator):
        return self.find_element(*locator).is_displayed()

    def high_light_element(self, locator):
        # 封装好的高亮显示页面元素的方法
        # 使用JavaScript代码将传入的页面元素对象的背景颜色和边框颜色分别
        # 设置为绿色和红色
        self.driver.execute_script("arguments[0].setAttribute('style',arguments[1]);",
                                   locator, "background:green ;border:2px solid red;")

    # 鼠标悬停
    def clickandHold(self, locator, log=None):
        if log:
            print(log)
        move_mouse = self.find_element(*locator)
        ActionChains(self.driver).move_to_element(move_mouse).perform()
        self.sleep(1)

    def clickHold_Text(self, text, log=None):
        """
        :param text: 文本
        :param log:
        :return: 鼠标悬停,通过文本形式
        """

        if log:
            print(log)
        move_mouse = self.by_text(text)
        try:
            if move_mouse:
                ActionChains(self.driver).move_to_element(move_mouse).perform()
                time.sleep(1)
            else:
                print('通过文本：{}获取元素失败!'.format(text))
                self.exit()
        except Exception as e:
            Log.error(str(e))
            return False

    def clickHold_Text1(self, text, log=None):
        """
        :param text: 文本
        :param log:
        :return: 鼠标悬停,通过文本形式
        """

        if log:
            print(log)
        try:
            move_mouse = self.getElementByText(text)
            ActionChains(self.driver).move_to_element(move_mouse).perform()
            time.sleep(1)
        except:
            raise ('元素定位失败')

    # 鼠标右键点击
    def rightClick(self, locator):
        Actionsaction = self.find_element(*locator)
        ActionChains(self.driver).context_click(Actionsaction).perform()
        self.sleep(1)

    # 双击鼠标左键
    def doubleClickMouse(self, locator):
        ele = self.find_element(*locator)
        action = ActionChains(self.driver)
        action.double_click(ele).perform()
        self.sleep(1)

    def doubleClickMouse_Text(self, text, log=None):
        """
        :param text: 页面指定文本
        :param log:
        :return:通过页面文本双击鼠标左键
        """
        if log:
            print(log)
        ele = self.getElementByText(text)
        if ele:
            action = ActionChains(self.driver)
            action.double_click(ele).perform()
            time.sleep(1)
        else:
            print('通过文本：{}获取元素失败!'.format(text))

    # 鼠标拖拽
    def dragDrop(self, locator, x, y):
        Actionsaction = self.find_element(*locator)
        ActionChains(self.driver).drag_and_drop_by_offset(Actionsaction, x, y).perform()
        self.sleep(1)

    def keyboard(self):
        """
        :return: 按下ESC键,并且松开
        """
        action = ActionChains(self.driver)
        action.key_down(Keys.CONTROL).send_keys(Keys.ESCAPE).key_up(Keys.CONTROL).perform()

    def isAlertPresent(self):
        try:
            self.driver.switch_to.alert().accept()
            return "true"
        except:
            return "false"

    def acceptalertdialog(self):
        flag = "false"
        times = 0
        while flag == "false":
            flag = self.isAlertPresent()
            times += 1
            time.sleep(1)
            if 5 == times:
                print(times)
                return

    # 退出
    def exit(self):
        self.driver.quit()

    # 回退
    def back(self):
        self.driver.back()
        time.sleep(1)

    # 刷新
    def refresh(self):
        self.driver.refresh()

    # 浏览器窗口最大
    def maxWindow(self):
        self.driver.maximize_window()

    def switchWindow(self, windowname):
        self.driver.switch_to.window(windowname)

    def switch_new_window(self):
        try:
            my_handle = self.driver.current_window_handle
            print("当前窗口：", my_handle)
            all_handles = self.driver.window_handles
            print("全部窗口", all_handles)
            new_handle = None
            for handle in all_handles:
                if handle == my_handle:
                    self.driver.close()
                else:
                    new_handle = handle
                    print("新窗口", new_handle)
            self.driver.switch_to.window(new_handle)
        except Exception as e:
            print("浏览器句柄切换异常：" + str(e))

    # 切换frame
    def switchFrame(self, frame):
        self.driver.switch_to.frame(frame)

    def win_alert(self):

        win = self.driver.switch_to.alert

        time.sleep(1)
        win.accept()

    def info_iframe(self, locator, log=None):

        """
        进入iframe
       :param loactor: 想要找到的元素位置
       :param log:
       :return:
        """
        if log:
            print(log)

        element = self.find_element(*locator)
        if element:
            self.driver.switch_to.frame(element)
        else:
            print('【ERROR】iframe没有定位到，请检查！')

    # 回退到上层frame
    def switchFrameParent(self):
        self.driver.switch_to.parent_frame()

    # 跳出iframe
    def switch_to_content(self):
        self.driver.switch_to.default_content()

    def windowHandles(self):
        return self.driver.window_handles

    def get_line_with_value(self, locator, content, linetype='tr', coltype='td'):
        """
        获取二维数组（e.g.table）中包含指定值的所在行及所在元素
        :param locator:table的定位方式
        :param content:需要匹配的目标值
        :param linetype:行标签， tr
        :param coltype:列标签， td
        :return:返回包含所在行及所在元素的数组或None
        """
        li_list = self.find_element(*locator).find_elements(By.TAG_NAME, linetype)
        for rindex, li in enumerate(li_list):  # 遍历每一个tr
            # 将每一个tr的数据根据td查询出来，返回结果为list对象
            elements = li.find_elements(By.TAG_NAME, coltype)
            for dindex, span in enumerate(elements):
                if content == span.text:
                    return [rindex, elements]

    def enabled(self, locator):
        """
        :param locator: 元素位置
        :return: 判断按钮是否变为灰色
        """
        element = self.find_element(*locator)
        if element:
            time.sleep(3)
            return_value = element.is_enabled()
            print(return_value)

        else:
            print("寻找状态失败")

    def implicitly_wait(self):

        self.driver.implicitly_wait(10)


if __name__ == "__main__":
    bp = BasePage()
